package com.linkoog.devtools.utils;

import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiAnnotation;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiClassOwner;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.impl.PsiManagerEx;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.indexing.FileBasedIndex;
import jdk.jfr.Description;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.List;
import java.util.Objects;

public class PsiClassUtils {


    @Nullable
    public static PsiClass findMainClass(final Module module, final String mainClassName) {
        return findMainClass(module.getProject(), mainClassName, module.getModuleRuntimeScope(true));
    }

    @Nullable
    public static PsiClass findMainClass(final Project project, final String mainClassName, final GlobalSearchScope scope) {
        if (project.isDefault() ||
                (DumbService.isDumb(project) &&
                        FileBasedIndex.getInstance().getCurrentDumbModeAccessType() == null &&
                        !DumbService.getInstance(project).isAlternativeResolveEnabled())) {
            return null;
        }
        final PsiManager psiManager = PsiManager.getInstance(project);
        final String shortName = StringUtil.getShortName(mainClassName);
        final String packageName = StringUtil.getPackageName(mainClassName);
        final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(psiManager.getProject());
        final PsiClass psiClass = psiFacade.findClass(StringUtil.getQualifiedName(packageName, shortName.replace('$', '.')), scope);
        return psiClass == null ? psiFacade.findClass(mainClassName, scope) : psiClass;
    }


    @Description("获取指定类的包名")
    public static @Nullable String getPackageName(@NotNull PsiClass psiClass) {
        String qualifiedName = psiClass.getQualifiedName();
        if (Objects.isNull(qualifiedName)) {
            return null;
        }

        //
        String fileName = psiClass.getName();
        if (Objects.isNull(fileName)) {
            return null;
        }

        if (qualifiedName.equals(fileName)){
            return null;
        }

        if (qualifiedName.endsWith(fileName)) {
            return qualifiedName.substring(0, qualifiedName.length() - fileName.length() -1);
        }

        return null;
    }


    /**
     *   解析PsiClass
     */
    public static PsiClass findPsiClass(Project project, String url, int psiElementOffset){
        if (project == null || url == null) return null;

        VirtualFile virtualFile = VirtualFileManager.getInstance().findFileByUrl(url);
        if (virtualFile == null) return null;

        PsiFile psiFile = VirtualFileUtils.getPsiFile(project, virtualFile);
        if (psiFile == null) return null;

        PsiElement psiElement = psiFile.findElementAt(psiElementOffset);
        return  PsiTreeUtil.getParentOfType(psiElement, PsiClass.class);
    }


    /**
     *   解析virtualFile的PsiClass
     */
    public static PsiClass[] getPsiClassArray(Project project, VirtualFile virtualFile){
        if (virtualFile == null || virtualFile.isDirectory())  return null;

        return DumbService.getInstance(project).runReadActionInSmartMode(()->{
            try {
                //PsiFile psiFile = PsiManagerEx.getInstanceEx(project).getFileManager().getCachedPsiFile(virtualFile);
                //PsiFile psiFile = VirtualFileUtils.getPsiFile(project, virtualFile);
                PsiManager psiManager = PsiManager.getInstance(project);
                PsiFile psiFile = psiManager.findFile(virtualFile);
                if (psiFile == null) return null;

                if (psiFile instanceof PsiClassOwner psiClassOwner){
                    if (psiClassOwner.isValid()){
                        PsiClass[] psiClasses =  psiClassOwner.getClasses();
                        if (psiClasses.length == 0) return null;
                        return psiClasses;
                    }
                }
            }catch (Throwable ignored){
            }
            return null;
        });
    }

    /**
     *   解析PsiClass的PsiAnnotation 注解
     */
    public static PsiAnnotation parseClassAnnotation(PsiClass psiClass, List<String> classAnnotationList, boolean findSuper) {
        if (psiClass == null || classAnnotationList == null || classAnnotationList.isEmpty()){
            return null;
        }

        PsiAnnotation psiAnnotation = doParseClassAnnotation(psiClass, classAnnotationList);
        if (psiAnnotation != null) {
            return psiAnnotation;
        }

        if(findSuper){
            PsiClass[] superPsiClassArray = psiClass.getSupers();
            for (PsiClass superPsiClass : superPsiClassArray) {
                PsiAnnotation annotation = doParseClassAnnotation(superPsiClass, classAnnotationList);
                if (annotation != null) {
                    return annotation;
                }
            }
        }

        return null;
    }

    private static PsiAnnotation doParseClassAnnotation(PsiClass psiClass, List<String> classAnnotationList) {
        for (String classAnnotationQualifiedName : classAnnotationList) {
            PsiAnnotation psiAnnotation = psiClass.getAnnotation(classAnnotationQualifiedName);
            if (psiAnnotation != null){
                return psiAnnotation;
            }
        }
        return null;
    }



}
